#ifndef     __MESSAGE_QUEUE_H
#define     __MESSAGE_QUEUE_H

#include "../rtx/rtx_os.h"
#include "../utils/nocopyable.h"

namespace rtos {

namespace lazy {

template <typename MsgType, uint32_t Capacity>
class MessageQueue : NoCopyable {
public:
    static constexpr uint32_t MsgSize = sizeof (MsgType);
    static constexpr uint32_t MqSize = osRtxMessageQueueMemSize(Capacity, MsgSize);

    void init(const char *name = "other") {
        osMessageQueueAttr_t attr;
        attr.name = name;
        attr.attr_bits = 0;
        attr.cb_mem = m_cb_mem;
        attr.cb_size = osRtxMessageQueueCbSize;
        attr.mq_mem = m_mq_mem;
        attr.mq_size = MqSize;
        m_id = osMessageQueueNew(Capacity, MsgSize, &attr);
    }

    inline osStatus_t post(const MsgType &msg) {
        return osMessageQueuePut(m_id, &msg, 0, 0);
    }

    inline osStatus_t poll(MsgType &msg, uint32_t timeout = osWaitForever) {
        return osMessageQueueGet(m_id, &msg, NULL, timeout);
    }

    inline osStatus_t get(MsgType &msg) {
        return osMessageQueueGet(m_id, &msg, NULL, 0);
    }

    inline MsgType take() {
        MsgType m;
        osMessageQueueGet(m_id, &m, NULL, osWaitForever);
        return m;
    }

    inline osStatus_t reset() {
        return osMessageQueueReset(m_id);
    }

private:
    osMessageQueueId_t m_id;
    uint64_t m_cb_mem[ (osRtxMessageQueueCbSize + 7) / 8 ];
    uint64_t m_mq_mem[ (MqSize + 7) / 8 ];
};

}


template <typename MsgType, uint32_t Capacity>
class MessageQueue : NoCopyable {
public:
    static constexpr uint32_t MsgSize = sizeof (MsgType);
    static constexpr uint32_t MqSize = osRtxMessageQueueMemSize(Capacity, MsgSize);

    MessageQueue(const char *name = "other") {
        osMessageQueueAttr_t attr;
        attr.name = name;
        attr.attr_bits = 0;
        attr.cb_mem = m_cb_mem;
        attr.cb_size = osRtxMessageQueueCbSize;
        attr.mq_mem = m_mq_mem;
        attr.mq_size = MqSize;
        m_id = osMessageQueueNew(Capacity, MsgSize, &attr);
    }

    inline osStatus_t post(const MsgType &msg) {
        return osMessageQueuePut(m_id, &msg, 0, 0);
    }

    inline osStatus_t poll(MsgType &msg, uint32_t timeout = osWaitForever) {
        return osMessageQueueGet(m_id, &msg, NULL, timeout);
    }

    inline osStatus_t get(MsgType &msg) {
        return osMessageQueueGet(m_id, &msg, NULL, 0);
    }

    inline MsgType take() {
        MsgType m;
        osMessageQueueGet(m_id, &m, NULL, osWaitForever);
        return m;
    }

    inline osStatus_t reset() {
        return osMessageQueueReset(m_id);
    }

private:
    osMessageQueueId_t m_id;
    uint64_t m_cb_mem[ (osRtxMessageQueueCbSize + 7) / 8 ];
    uint64_t m_mq_mem[ (MqSize + 7) / 8 ];
};

}




#endif
